package com.yq.ylmall.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yq.ylmall.constant.ProductConstant;
import com.yq.ylmall.dto.product.CategoryOperateDto;
import com.yq.ylmall.dto.product.RemoveDto;
import com.yq.ylmall.exception.ServiceException;
import com.yq.ylmall.model.product.Category;
import com.yq.ylmall.product.mapper.CategoryMapper;
import com.yq.ylmall.product.service.ICategoryService;
import com.yq.ylmall.product.service.IFileService;
import com.yq.ylmall.product.utils.CategoryHelper;
import com.yq.ylmall.product.utils.ExcelHelper;
import com.yq.ylmall.result.ResultCode;
import com.yq.ylmall.service.CacheService;
import com.yq.ylmall.vo.product.CategoryExcelVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品分类 服务实现类
 * </p>
 *
 * @author yzk789
 * @since 2024-05-30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements ICategoryService {

    private final IFileService fileService;
    private final CacheService cacheService;

    @Override // 添加缓存后，响应时间快了平均 40ms
    public String findAll() {
        // 查询缓存
        String cache = cacheService.get(ProductConstant.PRODUCT_CATEGORY_CACHE);
        if (StrUtil.isNotBlank(cache)) return cache; // 命中缓存，返回数据
        if (cache != null) return null; // 命中 "" (空缓存)，返回 null，防止缓存击穿

        // 未命中缓存，访问数据库
        List<Category> categories = baseMapper.selectList(
                Wrappers.<Category>lambdaQuery()
                        .orderByAsc(Category::getOrderNum)
        );
        // 查询数据库，数据为空，缓存空数据，并返回 null
        if (categories.isEmpty()) {
            cacheService.setEx(ProductConstant.PRODUCT_CATEGORY_CACHE, "", 3600, TimeUnit.SECONDS);
            return null;
        }
        // 递归构建分类数据，缓存到 Redis，并设置 1天过期时间
        String result = JSON.toJSONString(CategoryHelper.buildTree(categories));
        cacheService.setEx(ProductConstant.PRODUCT_CATEGORY_CACHE, result, 3600, TimeUnit.SECONDS);
        return result;
    }

    @Override
    @Transactional
    public Boolean doUpdate(CategoryOperateDto dto) {
        Category category = BeanUtil.copyProperties(dto, Category.class);
        int row = baseMapper.updateById(category);
        if (row == 0) return false;
        if (StrUtil.isNotBlank(dto.getOldImageUrl())) fileService.removeFile(dto.getOldImageUrl());
        cacheService.delete(ProductConstant.PRODUCT_CATEGORY_CACHE);
        return true;
    }

    @Override
    @Transactional
    public Boolean doRemoveById(RemoveDto dto) {
        int row = baseMapper.deleteById(dto.getId());
        if (row == 0) return false;
        if (StrUtil.isNotBlank(dto.getRemoveImg())) fileService.removeFile(dto.getRemoveImg());
        cacheService.delete(ProductConstant.PRODUCT_CATEGORY_CACHE);
        return true;
    }

    @Override
    @Transactional
    public Boolean doRemoveByIds(List<Long> ids) {
        int row = baseMapper.deleteBatchIds(ids);
        if (row == 0) {
            log.info("SQL执行异常：批量删除分类失败，ID：{}", ids.toString());
            return false;
        }
        List<Category> categories = baseMapper.selectList(Wrappers.<Category>lambdaQuery().select(Category::getImageUrl).in(Category::getId, ids));
        List<String> filenames = categories.stream().map(Category::getImageUrl).collect(Collectors.toList());
        if (!filenames.isEmpty()) fileService.removeFile(filenames);
        cacheService.delete(ProductConstant.PRODUCT_CATEGORY_CACHE);
        return true;
    }

    @Override
    public void exportData(HttpServletResponse response) {
        try {
            //1.设置响应头信息和其他信息
            // 设置响应结果类型
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("分类数据", "UTF-8");
            //设置响应头信息
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            //2.调用mapper方法查询所有分类，返回list集合
            List<Category> categoryList = baseMapper.selectList(null);
            List<CategoryExcelVo> categoryExcelVoList = new ArrayList<>();
            //类型转换
            for (Category category : categoryList) {
                CategoryExcelVo categoryExcelVo = new CategoryExcelVo();
                BeanUtils.copyProperties(category, categoryExcelVo);
                categoryExcelVoList.add(categoryExcelVo);
            }
            //3.调用easyexcel的write方法完成写操作
            EasyExcel.write(response.getOutputStream(), CategoryExcelVo.class)
                    .sheet("分类数据")
                    .doWrite(categoryExcelVoList);
        } catch (Exception e) {
            throw new ServiceException(ResultCode.FILE_DOWNLOAD_FAIL);
        }
    }

    @Override
    public void importData(MultipartFile file) {
        try {
            //创建监听器对象，传递mapper对象
            ExcelHelper<CategoryExcelVo> excelHelper = new ExcelHelper<>(baseMapper);
            //调用read方法读取excel数据
            EasyExcel.read(file.getInputStream(),
                    CategoryExcelVo.class,
                    excelHelper).sheet().doRead();
            cacheService.delete(ProductConstant.PRODUCT_CATEGORY_CACHE);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException(ResultCode.DATA_ERROR);
        }
    }

    @Override
    public List<Category> findByParentId(Long parentId) {
        // 根据分类id查询它下面的所有的子分类数据
        List<Category> categoryList = baseMapper.selectByParentId(parentId);
        if(!CollectionUtils.isEmpty(categoryList)) {

            // 遍历分类的集合，获取每一个分类数据
            categoryList.forEach(item -> {

                // 查询该分类下子分类的数量
                int count = baseMapper.countByParentId(item.getId());
                if(count > 0) {
                    item.setHasChildren(true);
                } else {
                    item.setHasChildren(false);
                }

            });
        }
        return categoryList;
    }

}
